home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 30
/
Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso
/
Aminet
/
gfx
/
show
/
FV21BETA-src.lha
/
FV21BETA-src
/
FV.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-09-17
|
73KB
|
2,547 lines
#include <classes/codec.h>
#include <codecs/jpeg.h>
#include <codecs/picture.h>
#include <cybergraphics/cybergraphics.h>
#include <devices/inputevent.h>
#include <dos/dosasl.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <exec/types.h>
#include <graphics/gfxbase.h>
#include <graphics/layers.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>
#include <proto/asl.h>
#include <proto/cybergraphics.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/icon.h>
#include <proto/intuition.h>
#include <proto/tower.h>
#include <proto/utility.h>
#include <string.h>
#include <utility/tagitem.h>
/*
END
*/
#define ERROR_INVALID_FILE 21
#define ERROR_EMPTY_FILE 22
#define ERROR_NO_SCREEN 23
#define ERROR_NO_WINDOW 24
#define ERROR_WHILE_DECODING 25
#define ERROR_EARLY_END_OF_FILE 26
#define ERROR_END_OF_STREAM 27
#define ERROR_UNKNOWN_FILETYPE 28
#define ERROR_NO_SCREENMODE 29
/* User wants the next picture while the current one was only partially decoded */
#define USER_NEXTPARTIAL 1
/* User wants the next picture while the current one was fully decoded */
#define USER_NEXTFULL 2
#define USER_EXIT 3
/* ColorConversion defines:
PALETTE : Color look-up table, 1 byte per pixel, ranges from 1-8 bits
FTC : Fake true color, 1 byte per pixel, ranges from 1-8 bits
GRAY : Gray-scale, 1 byte per pixel, ranges from 1-8 bits */
#define CC_PALETTE 0
#define CC_FTC 1
#define CC_GRAY 2
#define CC_TRUECOLOR 3
#define CC_UNKNOWN 255
/* ColorInput defines:
PALETTE : Color look-up table, 1 byte per pixel (after P2C), ranges from 1-8 bits
GRAY : Gray-scale, 1 byte per pixel (after P2C), ranges from 1-8 bits
RGB : True Color, 3 bytes per pixel (after P2C), always 24-bit
HAM : Hold-and-modify, 1 byte per pixel (after P2C), 6 or 8 bits
EHB : Extra-half-brite, 1 byte per pixel (after P2C), always 6 bits */
#define CI_PALETTE 0
#define CI_GRAY 1
#define CI_RGB 2
#define CI_HAM 3
#define CI_EHB 4
extern ULONG __stack=8192+4096;
/* working switches: FILES,ALL,ORDER,LEAVEMEM,DEBUG,INFO,F1-F10 */
char template[]="FILES/M,ALL/S,ORDER/K,DITHER/S,SCALE/S,DELAY/K/N,INFO/K,WAITFORPIC/S,"\
"ROM/S,POINTER/S,DEBUG/S,SM=SCREENMODE/K,COMMENT/K,"\
"LEAVEMEM/K/N,USECHIP/S,PUBSCREEN/K,GRAY=GREY/S,"\
"SLOWSWITCH/S,CAT/K/N,F1/K,F2/K,F3/K,F4/K,F5/K,F6/K,F7/K,F8/K,F9/K,F10/K"
#include "FV.hi"
ULONG leavemem=1024*4096;
UBYTE *par_info="%n (%xx%yx%d) %c";
struct {char **files;
ULONG all;
UBYTE *order;
ULONG dither;
ULONG scale;
ULONG *delay;
UBYTE *info;
ULONG waitforpic;
ULONG rom;
ULONG pointer;
ULONG debug;
char *screenmode;
char *comment;
ULONG *leavemem;
ULONG usechip;
char *pubscreen;
ULONG gray;
ULONG slowswitch;
ULONG *cat;
char *f1;
char *f2;
char *f3;
char *f4;
char *f5;
char *f6;
char *f7;
char *f8;
char *f9;
char *f10;} arglist={NULL};
char scrchoicetemplate[]="NOMW/N,NOMH/N,DEPTH/N,DESCRIPTION";
struct ScrChoice {
ULONG *nomw;
ULONG *nomh;
ULONG *depth;
UBYTE *description;
struct RDArgs *readargs;
ULONG modeid; /* if INVALID_ID then this ScrChoice structure is to be ignored */
struct ScrChoice *next;
};
struct ScrChoice *firstscrchoice;
char buffer[8192];
ULONG loadrgb32[3*256+2];
/* Structure which is used as a header for a block of data to be displayed now or in
the future */
struct DisplayData {
struct Node node;
UWORD row;
UWORD rowstodec;
UWORD pad;
struct LineHeader lh[8];
};
struct PicType {
BOOL(*recognisefunc)(struct ScreenNode *);
LONG(*initfunc)(struct ScreenNode *);
void(*exitfunc)(struct ScreenNode *);
LONG __asm(*decodefunc)(register __a0 struct ScreenNode *,register __d0 UWORD,register __a1 UBYTE *);
char *code;
};
ULONG __saveds __asm bfillhookfunc(register __a0 struct Hook *,register __a2 APTR,register __a1 APTR);
struct Hook bfillhook={0,0,bfillhookfunc,0,0};
struct ScrChoice *bestmodeid(struct ScreenNode *);
LONG openscreen(struct ScreenNode *);
void closescreen(struct ScreenNode *);
LONG checkmsg(void);
LONG decodepicture(struct ScreenNode *,struct PicType *);
void displaypicture(struct ScreenNode *,struct DisplayData *);
LONG initloader(struct ScreenNode *,ULONG);
LONG doloader(struct ScreenNode *);
void freeloader(struct ScreenNode *);
void infotext(struct ScreenNode *);
void makeinfostring(UBYTE *,UBYTE *,UWORD,struct ScreenNode *);
void copypalette(struct ScreenNode *,UBYTE *);
void printfault(LONG,UBYTE *);
struct ScreenNode *freescreennode(struct ScreenNode *);
LONG opennextscreen(struct ScreenNode *,struct ScreenNode *);
ULONG rangerandom(ULONG);
extern ULONG __asm RANDOM(register __d0 ULONG);
extern void __asm RGBTOFTC(register __a0 void *,register __a1 void *,register __d0 UWORD,register __d1 UWORD,register __d2 UWORD);
extern void __asm SCALERGB(register __a0 void *,register __a1 void *,register __d0 UWORD,register __d1 UWORD);
extern void __asm SCALEGRAY(register __a0 void *,register __a1 void *,register __d0 UWORD,register __d1 UWORD);
UBYTE ftctable[3*8]={0,1,0, 1,1,0, 1,1,1, 1,2,1, 2,2,1, 2,2,2, 2,3,2, 3,3,2};
BOOL recogniseJPEG(struct ScreenNode *);
LONG initJPEG(struct ScreenNode *);
void exitJPEG(struct ScreenNode *);
LONG __asm decodeJPEG(register __a0 struct ScreenNode *,register __d0 UWORD,register __a1 UBYTE *);
BOOL recogniseGIF(struct ScreenNode *);
LONG initGIF(struct ScreenNode *);
void exitGIF(struct ScreenNode *);
LONG __asm extern DECODEGIF(register __a0 struct ScreenNode *,register __d0 UWORD,register __a1 UBYTE *);
struct PicType pictypes[]={recogniseJPEG,initJPEG,exitJPEG,decodeJPEG,"JPEG",
recogniseGIF,initGIF,exitGIF,DECODEGIF,"GIF",
0,0,0,0,0};
struct Library *UtilityBase;
struct Library *CyberGfxBase;
struct Library *TowerBase;
extern struct ExecBase *SysBase;
struct GfxBase *GfxBase;
static ULONG BitMapDepth(struct BitMap *);
static void DeleteBitMap(struct BitMap *);
struct BitMap *CreateBitMap(LONG,LONG,LONG);
struct ScreenNode *activescreen=0;
void InitList(struct List *);
void debugreq(UBYTE *);
struct List snlist;
ULONG rndseed;
struct FileNode {
struct MinNode minnode;
UBYTE name[1]; /* name followed by comment */
};
struct Screen *wbscr;
UWORD wbfontysize=0;
ULONG main() {
struct ScrChoice *sc;
struct ScreenNode *sn;
struct RDArgs *readarg;
char **curfile;
ULONG errorcode,filecnt;
struct PicType *pictype;
UBYTE picdecoded;
UBYTE __aligned extendedap[sizeof(struct AnchorPath)+1024]={0};
struct AnchorPath *ap;
void *filepool;
void *scrchoicepool;
struct MinList filelist;
struct DateStamp ds;
ap=(struct AnchorPath *)extendedap;
ap->ap_Strlen=1020;
InitList(&snlist);
InitList((struct List *)&filelist);
errorcode=RETURN_FAIL;
if((DOSBase=(struct DosLibrary *)OpenLibrary("dos.library",37))!=0) {
if((IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",37))!=0) {
if((AslBase=OpenLibrary("asl.library",36))!=0) {
if((IconBase=OpenLibrary("icon.library",37))!=0) {
if((UtilityBase=OpenLibrary("utility.library",37))!=0) {
if((GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",37))!=0) {
TowerBase=OpenLibrary("tower.library",1);
CyberGfxBase=OpenLibrary("cybergraphics.library",40);
if((wbscr=LockPubScreen("Workbench"))!=0) {
/* Creating a nice randomseed */
DateStamp(&ds);
if((rndseed=(((ULONG)&filelist)^(ds.ds_Days<<16)^(ds.ds_Minute<<8)^(ds.ds_Tick>>1)) & 0x3fffffff)==0) {
rndseed=0x40000000;
}
PutStr("FastView 2.1 (18 November 1996) - Programmed by John Hendrikx\n");
if((readarg=ReadArgs(template,(LONG *)&arglist,0))!=0) {
/* Now override default values for any parameters passed in */
if(arglist.leavemem!=0) {
leavemem=*arglist.leavemem;
}
if(arglist.info!=0) {
if(*arglist.info!=0) {
par_info=arglist.info;
}
}
if(arglist.info!=0) {
wbfontysize=wbscr->Font->ta_YSize;
}
if((scrchoicepool=CreatePool(0,512,512))!=0) {
{
BPTR fh;
UBYTE *linebuf;
if((linebuf=AllocVec(1024,0))!=0) {
if((fh=Open("PROGDIR:fvmodes",MODE_OLDFILE))!=0) {
LONG line=1;
struct ScrChoice *sc;
while(FGets(fh,linebuf,1020)!=0) {
if(*linebuf!='*' && *linebuf!=';' && *linebuf!=0 && *linebuf!='#') {
if((sc=AllocPooled(scrchoicepool,sizeof(struct ScrChoice)))!=0) {
if((sc->readargs=AllocDosObject(DOS_RDARGS,0))!=0) {
sc->readargs->RDA_Source.CS_Buffer=linebuf;
sc->readargs->RDA_Source.CS_Length=strlen(linebuf);
sc->readargs->RDA_Flags=RDAF_NOPROMPT;
if(ReadArgs(scrchoicetemplate,(LONG *)sc,sc->readargs)!=0) {
sc->next=firstscrchoice;
firstscrchoice=sc;
sc->modeid=BestCModeIDTags(CYBRBIDTG_Depth,*sc->depth,CYBRBIDTG_NominalWidth,*sc->nomw,CYBRBIDTG_NominalHeight,*sc->nomh);
if(sc->modeid==INVALID_ID) {
VPrintf("fvmodes: unable to find a suitable screenmode for line %ld.",&line);
}
if(arglist.debug!=0) {
VPrintf("(DEBUG) At line %2ld: ",&line);
VPrintf("NOMW=%4ld ",sc->nomw);
VPrintf("NOMH=%4ld ",sc->nomh);
VPrintf("DEPTH=%2ld ",sc->depth);
VPrintf("MODEID=$%08lx ",&sc->modeid);
VPrintf("DESCRIPTION=%s\n",&sc->description);
}
}
else {
// FreePooled(scrchoicepool,sc,sizeof(struct ScrChoice));
VPrintf("fvmodes: error in line %ld.\n",&line);
break;
}
}
}
}
else if(*linebuf=='#') {
break;
}
line++;
}
Close(fh);
}
else {
PutStr("fvmodes: file not found.\n");
}
FreeVec(linebuf);
}
else {
PutStr("fvmodes: not enough memory for linebuffer.\n");
}
}
if((curfile=arglist.files)!=0) {
if((filepool=CreatePool(0,4096,4096))!=0) {
filecnt=0;
while(*curfile!=0) {
struct FileNode *fn;
errorcode=MatchFirst(*curfile,ap);
if(errorcode!=0 && errorcode!=ERROR_NO_MORE_ENTRIES) {
printfault(errorcode,*curfile);
break;
}
do {
if(ap->ap_Info.fib_EntryType>=0) {
if((ap->ap_Flags & APF_DIDDIR)==0 && arglist.all!=0) {
ap->ap_Flags|=APF_DODIR;
}
else {
ap->ap_Flags&=~APF_DIDDIR;
}
}
else {
UBYTE pass=0;
if(arglist.comment!=0) {
UBYTE space[80];
char *str;
char *str2;
str=arglist.comment;
for(;;) {
str2=str;
while(*str!=0 && *str!=',') {
str++;
}
strncpy(&space[0],str2,str-str2);
space[str-str2]=0;
if(strstr(&ap->ap_Info.fib_Comment[0],&space[0])==0) {
pass=1;
break;
}
if(*str++==0) {
break;
}
}
}
if(pass==0) {
filecnt++;
if((fn=AllocPooled(filepool,sizeof(struct FileNode)+strlen(&ap->ap_Buf[0])+1+strlen(&ap->ap_Info.fib_Comment[0])+1))!=0) {
strcpy(fn->name,&ap->ap_Buf[0]);
strcpy(&fn->name[strlen(&ap->ap_Buf[0])+1],&ap->ap_Info.fib_Comment[0]);
if(arglist.order!=0) {
struct FileNode *orderfn=(struct FileNode *)filelist.mlh_Head;
struct FileNode *next;
struct FileNode *prev;
WORD cnt;
ULONG rndval,rndcnt=0;
prev=orderfn;
switch(*arglist.order & 0xDF) {
case 'A':
for(;;) {
cnt=32;
next=(struct FileNode *)orderfn->minnode.mln_Succ;
while(next->minnode.mln_Succ!=0 && cnt--!=0) {
next=(struct FileNode *)next->minnode.mln_Succ;
}
if(next->minnode.mln_Succ==0) {
break;
}
if(Stricmp(FilePart(&orderfn->name[0]),FilePart(&fn->name[0]))>=0) {
orderfn=prev;
break;
}
prev=orderfn;
orderfn=next;
}
while(orderfn->minnode.mln_Succ!=0 && Stricmp(FilePart(&orderfn->name[0]),FilePart(&fn->name[0]))<0) {
orderfn=(struct FileNode *)orderfn->minnode.mln_Succ;
}
Insert((struct List *)&filelist,(struct Node *)&fn->minnode,(struct Node *)orderfn->minnode.mln_Pred);
break;
case 'P':
while(orderfn->minnode.mln_Succ!=0 && Stricmp(&orderfn->name[0],&fn->name[0])<0) {
orderfn=(struct FileNode *)orderfn->minnode.mln_Succ;
}
Insert((struct List *)&filelist,(struct Node *)&fn->minnode,(struct Node *)orderfn->minnode.mln_Pred);
break;
default:
rndval=rangerandom(filecnt);
while(orderfn->minnode.mln_Succ!=0 && rndcnt++<rndval) {
orderfn=(struct FileNode *)orderfn->minnode.mln_Succ;
}
Insert((struct List *)&filelist,(struct Node *)&fn->minnode,(struct Node *)orderfn->minnode.mln_Pred);
break;
}
}
else {
AddTail((struct List *)&filelist,(struct Node *)&fn->minnode);
}
}
else {
errorcode=ERROR_NO_FREE_STORE;
break;
}
}
}
} while((errorcode=MatchNext(ap))==0);
MatchEnd(ap);
if(errorcode!=ERROR_NO_MORE_ENTRIES) {
break;
}
curfile++;
}
if(errorcode==ERROR_NO_MORE_ENTRIES && filecnt!=0) {
struct FileNode *fn=(struct FileNode *)filelist.mlh_Head;
while(fn->minnode.mln_Succ!=0) {
picdecoded=FALSE;
if((sn=AllocVec(sizeof(struct ScreenNode),MEMF_PUBLIC|MEMF_CLEAR))!=0) {
AddTail(&snlist,&sn->node);
InitList(&sn->displaydata);
sn->fn=fn;
PutStr(&fn->name[0]);
PutStr("\n");
if((sn->fh=Open(&fn->name[0],MODE_OLDFILE))!=0) {
pictype=pictypes;
while(pictype->recognisefunc!=0) {
if(pictype->recognisefunc(sn)==TRUE) {
break;
}
Seek(sn->fh,0,OFFSET_BEGINNING);
pictype++;
}
if(pictype->recognisefunc!=0) {
if((errorcode=pictype->initfunc(sn))==0) {
if(arglist.debug!=0) {
ULONG arg[3];
arg[0]=sn->width;
arg[1]=sn->height;
arg[2]=sn->depth;
VPrintf("(DEBUG) Pic Info : %ldx%ldx%ld\n",&arg);
}
sn->renderw=sn->width;
sn->renderh=sn->height;
if((sc=bestmodeid(sn))!=0) {
sn->scrchoice=sc;
sn->modeid=sc->modeid;
/* if(sn->halvewidth==FALSE) {
sn->renderw=sn->width;
}
else {
sn->renderw=(sn->width+1)>>1;
}
sn->renderh=sn->height; */
/* if(sn->rerender==FALSE) {
sn->renderd=sn->depth;
if(sn->direct==TRUE) {
if(sn->ham==TRUE) {
sn->displayid|=HAM_KEY;
}
else {
sn->displayid|=EXTRAHALFBRITE_KEY;
}
}
}
else {
sn->renderd=8;
if(sn->gray==TRUE) {
if(sn->deep==FALSE) {
sn->renderd=4;
}
}
else {
sn->displayid|=HAM_KEY;
if(sn->deep==FALSE) {
sn->renderd=6;
}
}
} */
if(arglist.debug!=0) {
if(sn->colorinput==CI_PALETTE) {
PutStr("(DEBUG) ColorIn : Color look-up table\n");
}
else if(sn->colorinput==CI_GRAY) {
PutStr("(DEBUG) ColorIn : Gray\n");
}
else if(sn->colorinput==CI_RGB) {
PutStr("(DEBUG) ColorIn : 24-bit RGB\n");
}
else if(sn->colorinput==CI_HAM) {
PutStr("(DEBUG) ColorIn : HAM\n");
}
if(sn->colorconversion==CC_FTC) {
PutStr("(DEBUG) ColorOut : Fake TrueColor\n");
}
else if(sn->colorconversion==CC_PALETTE) {
PutStr("(DEBUG) ColorOut : Color look-up table\n");
}
else if(sn->colorconversion==CC_GRAY) {
PutStr("(DEBUG) ColorOut : Gray\n");
}
else if(sn->colorconversion==CC_TRUECOLOR) {
PutStr("(DEBUG) ColorOut : TrueColor\n");
}
else if(sn->colorconversion==CC_UNKNOWN) {
PutStr("(DEBUG) ColorOut : Unknown\n");
}
}
sn->outputline=0;
errorcode=decodepicture(sn,pictype);
picdecoded=TRUE;
}
else {
errorcode=ERROR_NO_SCREENMODE;
}
}
pictype->exitfunc(sn);
}
else {
errorcode=ERROR_UNKNOWN_FILETYPE;
}
freeloader(sn); /* *always* save to call */
if(sn->fh!=0) {
Close(sn->fh);
sn->fh=0;
}
}
else {
errorcode=IoErr();
}
}
else {
errorcode=ERROR_NO_FREE_STORE;
}
if(errorcode==USER_EXIT) {
break;
}
if(errorcode==USER_NEXTPARTIAL || picdecoded==FALSE) {
/* this "error" can only be returned by decodepicture when the
user pressed the LMB while the currently *visible* picture was
the one being decoded */
freescreennode(sn);
}
if(errorcode!=0 && errorcode!=USER_NEXTPARTIAL) {
printfault(errorcode,&fn->name[0]);
}
errorcode=0;
fn=(struct FileNode *)fn->minnode.mln_Succ;
}
if(errorcode==0 && activescreen!=0) {
while((errorcode=checkmsg())==0) {
WaitPort(activescreen->window->UserPort);
}
}
while(snlist.lh_Head->ln_Succ!=0) {
freescreennode((struct ScreenNode *)snlist.lh_Head);
}
}
DeletePool(filepool);
}
else {
PutStr("Couldn't allocate a memory pool\n");
}
}
else {
PutStr("We really should put up a file-requester now\n");
}
{
struct ScrChoice *sc;
sc=firstscrchoice;
while(sc!=0) {
FreeArgs(sc->readargs);
FreeDosObject(DOS_RDARGS,sc->readargs);
sc=sc->next;
}
}
DeletePool(scrchoicepool);
}
errorcode=0;
FreeArgs(readarg);
}
UnlockPubScreen(0,wbscr);
}
else {
PutStr("Couldn't open Workbench screen\n");
}
if(TowerBase!=0) {
CloseLibrary(TowerBase);
}
if(CyberGfxBase!=0) {
CloseLibrary(CyberGfxBase);
}
CloseLibrary((struct Library *)GfxBase);
}
else {
PutStr("Couldn't open graphics.library V37\n");
}
}
else {
PutStr("Couldn't open utility.library V37\n");
}
CloseLibrary((struct Library *)IconBase);
}
else {
PutStr("Couldn't open icon.library V37\n");
}
CloseLibrary((struct Library *)AslBase);
}
else {
PutStr("Couldn't open asl.library V36\n");
}
CloseLibrary((struct Library *)IntuitionBase);
}
else {
PutStr("Couldn't open intuition.library V37\n");
}
CloseLibrary((struct Library *)DOSBase);
}
return(errorcode);
}
ULONG rangerandom(ULONG range) {
rndseed=RANDOM(rndseed);
return(rndseed%range);
}
/* size must be at least 4 bytes or more */
void makeinfostring(UBYTE *str,UBYTE *info,UWORD size,struct ScreenNode *sn) {
UWORD len,n;
UBYTE *num;
UBYTE numspace[12];
UBYTE procent[]="%";
UBYTE c;
struct FileInfoBlock *fib;
if((fib=AllocVec(sizeof(struct FileInfoBlock),0))!=0) {
size-=2;
len=strlen(info);
for(n=0;n<len;n++) {
if(*info=='%') {
info++;
c=*info++;
if(c=='x') {
num=&numspace[0];
stci_d(num,sn->width);
}
else if(c=='y') {
num=&numspace[0];
stci_d(num,sn->height);
}
else if(c=='d') {
num=&numspace[0];
stci_d(num,sn->depth);
}
else if(c=='c') {
BPTR lock;
if((lock=Lock(&sn->fn->name[0],SHARED_LOCK))!=0) {
if(Examine(lock,fib)!=0) {
num=&fib->fib_Comment[0];
}
else {
num=&procent[1];
}
UnLock(lock);
}
else {
num=&procent[1];
}
}
else if(c=='n') {
num=FilePart(sn->fn->name);
}
else if(c=='N') {
num=sn->fn->name;
}
else {
num=procent;
}
while(size-->0 && *num!=0) {
*str++=*num++;
}
}
else {
*str++=*info++;
size--;
}
if(size<=0) {
break;
}
}
FreeVec(fib);
}
*str=0;
}
LONG checkmsg() {
struct IntuiMessage *msg;
ULONG class;
UWORD code,qualifier;
LONG errorcode;
UWORD action;
/* This routine should only pass through an error code or user choice to the
routines below when this routine absolutely has too! */
if(activescreen==0) {
if((errorcode=opennextscreen((struct ScreenNode *)snlist.lh_Head,0))!=0) {
/* this usually returns USER_NEXTPARTIAL */
return(errorcode);
}
}
while((msg=(struct IntuiMessage *)GetMsg(activescreen->window->UserPort))!=0) {
class=msg->Class;
code=msg->Code;
qualifier=msg->Qualifier;
ReplyMsg((struct Message *)msg);
action=0;
if(class==IDCMP_MOUSEBUTTONS) {
if(code==IECODE_LBUTTON) {
action=IECODE_LBUTTON;
}
else if(code==IECODE_RBUTTON) {
action=IECODE_RBUTTON;
}
}
else if(class==IDCMP_RAWKEY) {
if(code==64 || code==68 || code==67) {
/* Space, Return and Enter */
action=IECODE_LBUTTON;
}
else if(code==70 && (qualifier & IEQUALIFIER_LSHIFT+IEQUALIFIER_RSHIFT)!=0) {
/* Shift + Del */
if(activescreen->fh!=0) {
Close(activescreen->fh);
activescreen->fh=0;
}
if((errorcode=DeleteFile(&activescreen->fn->name[0]))==0) {
printfault(IoErr(),&activescreen->fn->name[0]);
}
action=IECODE_LBUTTON;
}
else if(code==69) {
/* Escape */
action=IECODE_RBUTTON;
}
else if(code>=80 && code<=89) {
/* Function key pressed */
char **a;
code-=80;
a=&arglist.f1;
a+=code;
if(*a!=0) {
UBYTE str[512];
makeinfostring(str,*a,512,activescreen);
if(activescreen->fh!=0) {
Close(activescreen->fh);
activescreen->fh=0;
}
Execute(str,0,Output());
infotext(activescreen);
// action=IECODE_LBUTTON;
}
}
else {
/* Handle scrolling */
WORD xs=0,ys=0;
if(code==79 || code==45) {
/* Left or NUM Left */
xs=16;
}
else if(code==78 || code==47) {
/* Right or NUM Right */
xs=-16;
}
else if(code==76 || code==62) {
/* Up or NUM Up */
ys=16;
}
else if(code==77 || code==30) {
/* Down or NUM Down */
ys=-16;
}
else if(code==29) {
/* NUM 1 */
xs=16;
ys=-16;
}
else if(code==31) {
/* NUM 3 */
xs=-16;
ys=-16;
}
else if(code==61) {
/* NUM 7 */
xs=16;
ys=16;
}
else if(code==63) {
/* NUM 9 */
xs=-16;
ys=16;
}
if(xs!=0 || ys!=0) {
qualifier&=0x33; /* Both alt en shift keys */
if((qualifier & IEQUALIFIER_LSHIFT+IEQUALIFIER_RSHIFT)!=0) {
xs<<=4;
ys<<=4;
}
else if((qualifier & IEQUALIFIER_LALT+IEQUALIFIER_RALT)!=0) {
xs>>=4;
ys>>=4;
}
if(activescreen->screen->TopEdge+ys>0) {
ys=-activescreen->screen->TopEdge;
}
// MoveScreen(activescreen->screen,xs,ys);
ScreenPosition(activescreen->screen,SPOS_RELATIVE,xs,ys,0,0);
}
}
}
if(action==IECODE_LBUTTON) {
if(activescreen->node.ln_Succ->ln_Succ==0) {
/* There is no next screen!! */
closescreen(activescreen);
activescreen=0;
return(USER_NEXTPARTIAL);
}
/* There is a next screen! Open that one! */
if((errorcode=opennextscreen((struct ScreenNode *)activescreen->node.ln_Succ,activescreen))!=0) {
/* this usually returns USER_NEXTPARTIAL */
activescreen=0;
return(errorcode);
}
/* next screen was opened succesfully, and previous screen was closed.
No need to tell the decoder what happened, just let it continue :-) */
}
else if(action==IECODE_RBUTTON) {
return(USER_EXIT);
}
}
/* Nothing important enough happened to let the decoding loop worry about */
return(0);
}
void debugreq(UBYTE *text) {
struct EasyStruct es;
es.es_StructSize=sizeof(struct EasyStruct);
es.es_Flags=0;
es.es_Title="FastView Debug requester";
es.es_TextFormat=text;
es.es_GadgetFormat="Ok";
EasyRequestArgs(0,&es,0,0);
}
/* sn should be the first or second screennode in the list. cursn should be zero or
be the first screennode in the list. If cursn is non-zero then this routine will always
close, delink & free this screennode! */
LONG opennextscreen(struct ScreenNode *sn,struct ScreenNode *cursn) {
LONG errorcode;
UWORD divx,divy;
divx=*sn->scrchoice->nomw/sn->renderw;
divy=*sn->scrchoice->nomh/sn->renderh;
if(divx>divy) {
divx=divy;
}
if(divx>1) {
if(divx>4) {
divx=4;
}
sn->renderw*=divx;
sn->renderh*=divx;
}
while((errorcode=openscreen(sn))!=0) {
closescreen(sn);
if(cursn!=0) {
freescreennode(cursn);
cursn=0;
continue;
}
if(sn->renderw>320 && sn->renderh>200) {
/* inaccurate scaling to 3/4's */
sn->renderw=((((ULONG)sn->renderw)<<1)+sn->renderw)>>2;
sn->renderh=((((ULONG)sn->renderh)<<1)+sn->renderh)>>2;
continue;
}
printfault(errorcode,&activescreen->fn->name[0]);
/* This screen couldn't be opened, not even after closing the current screen
(if it was available) */
if(sn->node.ln_Succ->ln_Succ!=0) {
/* This isn't the screen which is currently being decoded
so we only need to delink and free the screennode */
sn=freescreennode(sn);
/* the while loop will attempt to retry the procedure... */
}
else {
/* This is the screen currently being decoded... */
return(USER_NEXTPARTIAL);
}
}
/* Screen opened succesfully */
if(cursn!=0) {
freescreennode(cursn);
}
return(0);
}
/* This routine opens the correct screen and if necessary initializes its palette */
LONG openscreen(struct ScreenNode *sn) {
ULONG colortag;
WORD n,c;
ULONG color;
ULONG w,h;
UBYTE *pal;
struct ScrChoice *sc;
sc=sn->scrchoice;
if(SysBase->LibNode.lib_Version>=39) {
colortag=SA_Colors32;
}
else {
colortag=SA_Colors;
}
loadrgb32[0]=0;
/* All this routine does is open the correct screen based on the info
in the ScreenNode. The errorcode returned is zero if the opening
the screen went okay */
c=1<<*sc->depth;
if(sn->colorconversion==CC_GRAY) {
if(colortag==SA_Colors) {
for(n=0; n<c; n++) {
color=(((255*n)/(c-1)) & 0xFF)>>4;
loadrgb32[n<<1]=(n<<16)+color;
loadrgb32[(n<<1)+1]=(color<<16)+color;
}
loadrgb32[n<<1]=0xffff0000;
}
else {
loadrgb32[0]=c<<16;
for(n=0; n<c; n++) {
color=((255*n)/(c-1)) & 0xFF;
color=(color<<24)+(color<<16)+(color<<8)+color;
loadrgb32[n*3+1]=color;
loadrgb32[n*3+2]=color;
loadrgb32[n*3+3]=color;
}
loadrgb32[c*3+1]=0;
}
sn->bestpen=c-1;
}
else if(sn->colorconversion==CC_FTC) {
UBYTE r,g,b,rm,gm,bm,rl,gl,bl;
r=ftctable[*sc->depth*3-3];
g=ftctable[*sc->depth*3-2];
b=ftctable[*sc->depth*3-1];
rm=((1<<r)-1)<<g<<b;
gm=((1<<g)-1)<<b;
bm=((1<<b)-1);
rl=16-r-g-b;
gl=16-g-b;
bl=16-b;
if(colortag==SA_Colors) {
for(n=0; n<c; n++) {
color=(n & rm)<<rl;
color=color+(color>>r);
color=color+(color>>r*2);
loadrgb32[(n<<1)]=(n<<16)+(color>>12);
color=(n & gm)<<gl;
color=color+(color>>g);
color=color+(color>>g*2);
loadrgb32[(n<<1)+1]=(color>>12)<<16;
color=(n & bm)<<bl;
color=color+(color>>b);
color=color+(color>>b*2);
loadrgb32[(n<<1)+1]|=(color>>12);
}
loadrgb32[n<<1]=0xffff0000;
}
else {
loadrgb32[0]=c<<16;
for(n=0; n<c; n++) {
color=(n & rm)<<rl<<16;
color=color+(color>>r);
color=color+(color>>r*2);
color=color+(color>>r*4);
loadrgb32[n*3+1]=color;
color=(n & gm)<<gl<<16;
color=color+(color>>g);
color=color+(color>>g*2);
color=color+(color>>g*4);
loadrgb32[n*3+2]=color;
color=(n & bm)<<bl<<16;
color=color+(color>>b);
color=color+(color>>b*2);
color=color+(color>>b*4);
loadrgb32[n*3+3]=color;
}
loadrgb32[c*3+1]=0;
}
sn->bestpen=c-1;
}
else if(sn->colorconversion==CC_PALETTE) {
WORD diff,bestdiff=0;
WORD r,g,b;
c=sn->colors;
pal=sn->palette;
if(colortag==SA_Colors) {
for(n=0; n<c; n++) {
color=(*(UWORD *)pal++)>>4;
loadrgb32[n<<1]=(n<<16)+color;
color=(*pal++)>>4;
loadrgb32[(n<<1)+1]=(color<<16);
color=(*pal++)>>4;
loadrgb32[(n<<1)+1]+=color;
}
loadrgb32[n<<1]=0xffff0000;
}
else {
loadrgb32[0]=c<<16;
for(n=0; n<c; n++) {
color=*(UWORD *)pal;
pal+=2;
color=(color<<24)+(color<<16)+(color<<8)+color;
loadrgb32[n*3+1]=color;
color=*pal++;
color=(color<<24)+(color<<16)+(color<<8)+color;
loadrgb32[n*3+2]=color;
color=*pal++;
color=(color<<24)+(color<<16)+(color<<8)+color;
loadrgb32[n*3+3]=color;
}
loadrgb32[c*3+1]=0;
}
pal=sn->palette;
r=*(UWORD *)pal;
pal+=2;
g=*pal++;
b=*pal++;
for(n=1; n<c; n++) {
color=*(UWORD *)pal;
pal+=2;
diff=__builtin_abs(r-color);
diff+=__builtin_abs(g-*pal++);
diff+=__builtin_abs(b-*pal++);
if(diff>bestdiff) {
bestdiff=diff;
sn->bestpen=n;
}
}
}
else {
if(colortag==SA_Colors) {
loadrgb32[0]=0;
loadrgb32[1]=0;
loadrgb32[2]=(1<<16)+0xf;
loadrgb32[3]=(0x0f<<16)+0x0f;
loadrgb32[4]=0xffff0000;
}
else {
loadrgb32[0]=2<<16;
loadrgb32[1]=0;
loadrgb32[2]=0;
loadrgb32[3]=0;
loadrgb32[4]=0xffffffff;
loadrgb32[5]=0xffffffff;
loadrgb32[6]=0xffffffff;
loadrgb32[7]=0;
}
sn->bestpen=1;
}
/* renderw and renderh in combination with width and height of the ScreenNode structure
determine the scaling factors. */
sn->scalexfactor=(((ULONG)sn->renderw)<<12)/sn->width;
sn->scaleyfactor=(((ULONG)sn->renderh)<<12)/sn->height;
w=(sn->renderw+31) & 0xffffffe0;
h=(sn->renderh+wbfontysize+7) & 0xfffffff8;
if(w<*sn->scrchoice->nomw) {
w=*sn->scrchoice->nomw;
}
if(h<128) {
h=128;
}
if(arglist.debug!=0) {
ULONG arg[4];
arg[0]=w;
arg[1]=h;
arg[2]=*sc->depth;
arg[3]=sc->modeid;
VPrintf("(DEBUG) OpenScreen: %ldx%ldx%ld ModeID: $%08lx\n",&arg);
}
/* A big hack to prevent the default screenfont opencount from reaching zero
when a screen failed to open */
GfxBase->DefaultFont->tf_Accessors++;
if((sn->screen=OpenScreenTags(0,SA_Left,0,SA_Width,w,SA_Height,h,SA_BackFill,LAYERS_NOBACKFILL,
SA_Depth,*sc->depth,SA_Quiet,TRUE,SA_DisplayID,sn->modeid,
SA_Overscan,OSCAN_STANDARD,SA_AutoScroll,TRUE,SA_Font,wbscr->Font,
colortag,&loadrgb32,TAG_DONE))!=0) {
GfxBase->DefaultFont->tf_Accessors--;
if((sn->window=OpenWindowTags(0,WA_IDCMP,IDCMP_MOUSEBUTTONS|IDCMP_RAWKEY,
// WA_BackFill,&bfillhook, or WA_BackFill, LAYERS_NOBACKFILL
WA_Borderless,TRUE,WA_Activate,TRUE,WA_RMBTrap,TRUE,
WA_CustomScreen,sn->screen,TAG_DONE))!=0) {
if(sn->tempbm=CreateBitMap(sn->width,8,BitMapDepth(sn->screen->RastPort.BitMap))) {
struct Node *node;
InitRastPort(&sn->temprp);
sn->temprp.BitMap=sn->tempbm;
/* We load the palette again here because some gfx-cards use a 12-bit palette
with the SA_Colors32 tag passed to OpenScreen() */
if(colortag==SA_Colors32) {
LoadRGB32(&sn->screen->ViewPort,(ULONG *)&loadrgb32);
}
infotext(sn);
/* Display any data available in the DisplayData structure and free it */
while(sn->displaydata.lh_Head->ln_Succ!=0) {
node=sn->displaydata.lh_Head;
displaypicture(sn,(struct DisplayData *)node);
Remove(node);
FreeVec(node);
}
/* Everything went okay */
activescreen=sn;
return(0);
}
}
else {
return(ERROR_NO_WINDOW);
}
}
else {
return(ERROR_NO_SCREEN);
}
}
void infotext(struct ScreenNode *sn) {
/* Display the info text above the picture if wanted */
if(arglist.info!=0) {
UBYTE str[256];
SetAPen(sn->window->RPort,0);
RectFill(sn->window->RPort,0,0,sn->screen->Width-1,wbfontysize-1);
makeinfostring(&str[0],par_info,256,sn);
SetAPen(sn->window->RPort,sn->bestpen);
Move(sn->window->RPort,0,sn->window->RPort->TxBaseline);
Text(sn->window->RPort,str,strlen(str));
}
}
/* Closes the screen and releases any other resources allocated by openscreen.
This routine is safe to call even if no screen or resources have been allocated. */
void closescreen(struct ScreenNode *sn) {
DeleteBitMap(sn->tempbm);
sn->tempbm=0;
if(sn->window!=0) {
CloseWindow(sn->window);
sn->window=0;
}
if(sn->screen!=0) {
CloseScreen(sn->screen);
sn->screen=0;
}
}
/* Deallocates a ScreenNode completely and all resources (if any) associated
with it. It returns the next ScreenNode, or 0 if there is none */
struct ScreenNode *freescreennode(struct ScreenNode *sn) {
struct ScreenNode *nextsn;
struct Node *node;
/* First close the screen (if any) */
closescreen(sn);
if(sn->fh!=0) {
Close(sn->fh);
}
while(sn->displaydata.lh_Head->ln_Succ!=0) {
node=sn->displaydata.lh_Head;
Remove(node);
FreeVec(node);
}
nextsn=(struct ScreenNode *)sn->node.ln_Succ;
/* Delink this node from the list */
Remove((struct Node *)sn);
/* Free the ScreenNode structure */
FreeVec(sn);
return(nextsn);
}
/* This routine scans through the ScrChoice structures and returns a pointer
to the one best matching the requirements. It also sets some fields in the
ScreenNode structure for the conversion and rendering routines. */
struct ScrChoice *bestmodeid(struct ScreenNode *sn) {
struct ScrChoice *sc;
struct ScrChoice *bestsc;
LONG a;
LONG cursize,bestsize=0x7fffffff;
UBYTE curcc,bestcc=0;
UBYTE flag;
sc=firstscrchoice;
bestsc=0;
while(sc!=0) {
if(sc->modeid!=INVALID_ID) {
/* Compare size of picture with the size of the screen; penalties are given
if the screen is too big or too small */
a=*sc->nomw-sn->width;
if(a<0) {
a=-4*a;
}
cursize=*sc->nomh-sn->height;
if(cursize<0) {
cursize=-4*cursize;
}
cursize+=a;
/* Check what kind of ColorConversion is needed to display the picture onto this
screen */
if(sn->colorinput==CI_PALETTE) {
if(sn->depth<=*sc->depth) {
curcc=CC_PALETTE;
}
else {
curcc=CC_UNKNOWN;
}
}
else if(sn->colorinput==CI_GRAY) {
if(*sc->depth<=8) {
curcc=CC_GRAY;
}
else {
curcc=CC_UNKNOWN;
}
}
else if(sn->colorinput==CI_RGB) {
if(*sc->depth<=8) {
curcc=CC_FTC;
}
else {
curcc=CC_TRUECOLOR;
}
}
else {
curcc=CC_UNKNOWN;
}
/* Now see if this mode is better suited than a previously found mode (if any) */
flag=0;
if(arglist.debug!=0) {
ULONG arg[4];
if(bestsc!=0) {
arg[0]=bestsc->modeid;
}
else {
arg[0]=0;
}
arg[1]=cursize;
arg[2]=sn->colorinput;
arg[3]=curcc;
VPrintf("(DEBUG) bestmodeid: $%08lx cursize: %5ld colorin: %3ld colorconv: %3ld\n",&arg);
}
if(curcc!=CC_UNKNOWN) {
if(sn->colorinput==CI_RGB) {
if(curcc==CC_TRUECOLOR) {
if(bestcc!=CC_TRUECOLOR || cursize<bestsize) {
flag=1;
}
}
else if(bestcc!=CC_TRUECOLOR && cursize<bestsize) {
flag=1;
}
}
else if(sn->colorinput==CI_PALETTE) {
/* if input is CI_PALETTE and output-depth is good enough to display the palette but
less than the bestoutput-depth then set flag */
if(*sc->depth>=sn->depth && (bestsc==0 || *bestsc->depth>*sc->depth)) {
flag=1;
}
if(cursize<bestsize) {
flag=1;
}
}
else if(sn->colorinput==CI_GRAY) {
if(cursize<bestsize) {
flag=1;
}
}
}
if(flag!=0) {
bestsc=sc;
bestcc=curcc;
bestsize=cursize;
}
}
sc=sc->next;
}
sn->colorconversion=bestcc;
sn->renderd=*bestsc->depth;
return(bestsc);
}
/* Special print-fault replacement */
void printfault(LONG errorcode,UBYTE *header) {
if(errorcode>20 && errorcode<50) {
VPrintf("%s: ",&header);
switch(errorcode) {
case ERROR_INVALID_FILE:
PutStr("File is invalid\n"); break;
case ERROR_EMPTY_FILE:
PutStr("File does not contain any pictures\n"); break;
case ERROR_NO_SCREEN:
PutStr("Couldn't open a screen\n"); break;
case ERROR_NO_WINDOW:
PutStr("Couldn't open a window\n"); break;
case ERROR_WHILE_DECODING:
PutStr("Error while decoding; file may be corrupt\n"); break;
case ERROR_EARLY_END_OF_FILE:
PutStr("Unexpected end of file encountered; file may be corrupt\n"); break;
case ERROR_END_OF_STREAM:
PutStr("Unexpected end of encoded data; file may be corrupt\n"); break;
case ERROR_UNKNOWN_FILETYPE:
PutStr("Filetype not recognized\n"); break;
case ERROR_NO_SCREENMODE:
PutStr("No suitable screenmode found\n"); break;
}
}
else {
PrintFault(errorcode,header);
}
}
/* Loads data from disk for easy access by the decoding routines. The minsize
parameter passed to initloader determines the minimum amount of bytes which
should be present in the buffer before returning (this will be rounded up to
some comfortable number if necessary). This routine returns a (DOS) errorcode
in case of failure or zero if everything went okay. */
LONG doloader(struct ScreenNode *sn) {
ULONG temp,size;
LONG res;
if(sn->fileptr > sn->loaderbuf+sn->loaderbufsize/2) {
/* There aren't enough bytes in the buffer to fill the demand. We will need
to move the resting portion of the buffer to the start of the buffer, and
fill the newly created void with data from the file. */
temp=(ULONG)sn->fileptr & 0xfffffff8;
size=(ULONG)(sn->loaderbuf+sn->loaderbufsize-temp);
CopyMemQuick((ULONG *)temp,sn->loaderbuf,size);
sn->fileptr-=sn->loaderbufsize-size;
if((res=Read(sn->fh,sn->loaderbuf+size,sn->loaderbufsize-size))==-1) {
return(IoErr());
}
sn->bytesinloaderbuf=size+res;
}
if(sn->loaderbuf+sn->bytesinloaderbuf<sn->fileptr) {
/* The fileptr is located beyond the end of the file, return an error! */
return(ERROR_EARLY_END_OF_FILE);
}
return(0);
}
/* minsize is the number of bytes which the doloader routine should atleast have present
in the loaderbuffer at exit of the routine for proper functioning of the routine which
make use of the buffering routines. */
LONG initloader(struct ScreenNode *sn,ULONG minsize) {
sn->loaderbufsize=((minsize+2047) & 0xfffff800)*2;
if((sn->loaderbuf=AllocVec(sn->loaderbufsize,MEMF_ANY))!=0) {
sn->fileptr=sn->loaderbuf;
if((sn->bytesinloaderbuf=Read(sn->fh,sn->loaderbuf,sn->loaderbufsize))==-1) {
return(IoErr());
}
}
else {
return(ERROR_NO_FREE_STORE);
}
return(0);
}
/* freeloader frees all resources allocated by initloader. It is safe to call this
even if initloader was never called. This function must be called if initloader
was called, even if initloader returned an error. */
void freeloader(struct ScreenNode *sn) {
if(sn->loaderbuf!=0) {
FreeVec(sn->loaderbuf);
sn->loaderbuf=0;
}
}
BOOL recogniseGIF(struct ScreenNode *sn) {
UBYTE buf[6];
if(Read(sn->fh,buf,6)==6) {
if((buf[0]=='G') && (buf[1]=='I') && (buf[2]=='F') && (buf[3]=='8')) {
if((buf[4]=='7') || (buf[4]=='9')) {
if(buf[5]=='a') {
return(TRUE);
}
}
}
}
return(FALSE);
}
struct GIF {
WORD size; // initial code size, also used when a clear-code is detected
WORD cursize;
WORD clearcode;
WORD endcode;
WORD newcodes;
WORD topslot;
WORD slot;
WORD navailbytes;
WORD nbitsleft;
WORD shiftreg;
UBYTE *suffix;
UWORD *prefix;
UBYTE *stack;
UBYTE *sp;
UWORD oc;
UWORD fc;
UWORD row;
UBYTE interlaced;
};
LONG initGIF(struct ScreenNode *sn) {
UBYTE buf[10];
UBYTE tempcmap[256*3];
ULONG colmapsize;
LONG errorcode;
struct GIF *data;
data=(struct GIF *)&sn->data;
if(Read(sn->fh,buf,7)==7) {
sn->depth=(buf[4] & 0x07)+1;
sn->colors=1<<sn->depth;
if((buf[4] & 0x80)!=0) {
colmapsize=sn->colors*3;
if(Read(sn->fh,tempcmap,colmapsize)==colmapsize) {
copypalette(sn,tempcmap);
}
else {
return(ERROR_INVALID_FILE);
}
}
for(;;) {
if(Read(sn->fh,buf,2)!=2) {
return(ERROR_INVALID_FILE);
}
if(buf[0]=='!') {
for(;;) {
if(Read(sn->fh,buf,1)!=1) {
return(ERROR_INVALID_FILE);
}
if(buf[0]==0) {
break;
}
if(Seek(sn->fh,(LONG)buf[0],OFFSET_CURRENT)==-1) {
return(IoErr());
}
}
}
else {
break;
}
}
if(buf[0]==',') {
if(Read(sn->fh,&buf[2],8)==8) {
sn->height=(UWORD)buf[7]+((UWORD)buf[8]<<8);
sn->width=(UWORD)buf[5]+((UWORD)buf[6]<<8);
if((buf[9] & 0x80)!=0) {
sn->depth=(buf[9] & 0x07)+1;
sn->colors=1<<sn->depth;
colmapsize=sn->colors*3;
if(Read(sn->fh,tempcmap,colmapsize)==colmapsize) {
copypalette(sn,tempcmap);
}
else {
return(ERROR_INVALID_FILE);
}
}
if((buf[9] & 0x40)!=0) {
data->interlaced=4;
}
else {
data->interlaced=0;
}
sn->bytesperrow=sn->width;
sn->bytesperpixel=1;
sn->colorinput=CI_PALETTE;
sn->aspectx=640;
sn->aspecty=480;
/* All done, now follows the actual "raster data", all that rests now is
to init some variables for the decoder. */
if((errorcode=initloader(sn,((ULONG)sn->width)<<4))==0) {
data->size=*sn->fileptr++;
if(data->size<2 || data->size>9) {
return(ERROR_INVALID_FILE);
}
data->cursize=data->size+1;
data->topslot=1<<data->cursize;
data->clearcode=1<<data->size;
data->endcode=data->clearcode+1;
data->slot=data->newcodes=data->endcode+1;
data->navailbytes=data->nbitsleft=0;
if((data->suffix=AllocVec(4096+4096+8192,MEMF_CLEAR))!=0) {
data->prefix=(UWORD *)(data->suffix+8192);
data->stack=data->suffix+4096;
data->sp=data->stack;
return(0);
}
return(ERROR_NO_FREE_STORE);
}
return(errorcode);
}
}
}
return(ERROR_INVALID_FILE);
}
void exitGIF(struct ScreenNode *sn) {
struct GIF *data;
data=(struct GIF *)&sn->data;
freeloader(sn);
FreeVec(data->suffix);
}
void copypalette(struct ScreenNode *sn,UBYTE *pal) {
UBYTE *palptr;
UWORD n;
palptr=sn->palette;
for(n=0;n<sn->colors;n++) {
*(UWORD *)palptr=*pal++;
palptr+=2;
*palptr++=*pal++;
*palptr++=*pal++;
}
}
BOOL recogniseJPEG(struct ScreenNode *sn) {
if(FGetC(sn->fh)==0xFF) {
if(FGetC(sn->fh)==0xD8) {
return(TRUE);
}
}
// if(TowerBase!=0) {
// }
return(FALSE);
}
struct JPEG {
APTR obj;
UWORD row;
}; /* do not exceed 44 bytes */
LONG initJPEG(struct ScreenNode *sn) {
struct JPEG *data;
ULONG error;
ULONG colorspace,width,height;
data=(struct JPEG *)&sn->data;
Seek(sn->fh,0,OFFSET_BEGINNING);
if(data->obj=NewExtObject(JPEGCODEC,CDA_StreamType,CDST_FILE,
CDA_Stream,sn->fh,TAG_DONE)) {
if((error=DoMethod(data->obj,CDM_READHEADER))==HEADER_READY) {
if(GetAttr(PCDA_ColorSpace,data->obj,&colorspace)
&& GetAttr(PCDA_Width,data->obj,&width)
&& GetAttr(PCDA_Height,data->obj,&height)) {
sn->width=width;
sn->height=height;
if(colorspace!=PCDCS_GRAYSCALE) {
colorspace=PCDCS_RGB;
sn->depth=24;
sn->bytesperrow=sn->width*3;
sn->bytesperpixel=3;
sn->colorinput=CI_RGB;
}
else {
sn->depth=8;
sn->colors=256;
sn->bytesperrow=sn->width;
sn->bytesperpixel=1;
sn->colorinput=CI_GRAY;
}
SetAttrs(data->obj,PCDA_ColorSpace,colorspace,TAG_DONE);
if(DoMethod(data->obj,CDM_START)!=0) {
sn->truecolor=TRUE;
sn->aspectx=640;
sn->aspecty=480;
return(0);
}
else {
return(ERROR_NO_FREE_STORE);
}
}
else {
return(ERROR_INVALID_FILE);
}
}
else if(error==HEADER_EMPTY) {
return(ERROR_EMPTY_FILE);
}
else {
return(ERROR_INVALID_FILE);
}
}
else {
return(ERROR_NO_FREE_STORE);
}
}
void exitJPEG(struct ScreenNode *sn) {
struct JPEG *data;
data=(struct JPEG *)&sn->data;
if(data->obj!=0) {
DisposeExtObject(data->obj);
}
}
/* The decode functions return an errorcode if something went wrong during the
decoding process. */
LONG __asm decodeJPEG(register __a0 struct ScreenNode *sn,register __d0 UWORD rows,register __a1 UBYTE *buffer) {
struct JPEG *data;
struct LineHeader *lh=(struct LineHeader *)(buffer-(sizeof(struct LineHeader)<<3));
data=(struct JPEG *)&sn->data;
while(rows--!=0) {
if(DoMethod(data->obj,CDM_PROCESS,buffer,sn->bytesperrow)!=sn->bytesperrow) {
return(ERROR_WHILE_DECODING);
}
buffer+=sn->bytesperrow;
lh->row=data->row++;
lh->repeatrow=1;
lh++;
}
return(0);
}
LONG decodepicture(struct ScreenNode *sn,struct PicType *pictype) {
UBYTE *buf;
UWORD row=0;
UWORD rowstodec;
LONG errorcode=0;
struct DisplayData *dd=0;
while((rowstodec=sn->height-row)>0) {
if((errorcode=checkmsg())!=0) {
break;
}
if((errorcode=doloader(sn))!=0) {
break;
}
if(rowstodec>8) {
rowstodec=8;
}
while(dd==0) {
if(sn->screen!=0 || AvailMem(MEMF_FAST)>leavemem) {
if((dd=(struct DisplayData *)AllocVec(sizeof(struct DisplayData)+sn->bytesperrow*8,0))!=0) {
buf=(UBYTE *)dd+sizeof(struct DisplayData);
dd->node.ln_Succ=0;
dd->node.ln_Pred=0;
dd->row=row;
dd->rowstodec=rowstodec;
}
}
if(sn->screen!=0 || dd!=0) {
break;
}
/* This isn't the picture currently being displayed, and there either was too little
memory left to allocate the buffer, the largest block was too small or no memory
was allocated because of the leavemem limit. In any case, no buffer has been
allocated and we need to wait until more memory is available before retrying. */
WaitPort(activescreen->window->UserPort);
if((errorcode=checkmsg())!=0) {
break;
}
}
/* als errorcode al ongelijk nul was (bijv. USER_EXIT) dan break */
if(errorcode!=0) {
break;
}
if(dd==0) {
errorcode=ERROR_NO_FREE_STORE;
break;
}
errorcode=pictype->decodefunc(sn,rowstodec,buf);
if(sn->colorconversion==CC_FTC) {
RGBTOFTC(buf,buf,sn->width,rowstodec,sn->renderd);
sn->colorinput=CI_PALETTE;
}
/* check if there is a screen for this ScreenNode, if not then store the decoded data */
if(sn->screen!=0) {
dd->row=row;
dd->rowstodec=rowstodec;
displaypicture(sn,dd);
}
else {
AddTail(&sn->displaydata,&dd->node);
dd=0; /* make sure a new buffer is allocated */
}
row+=rowstodec;
if(errorcode!=0) {
break;
}
}
FreeVec(dd);
if(errorcode==0 && rowstodec!=0) {
return(ERROR_WHILE_DECODING);
}
return(errorcode);
}
/*
RECTFMT_LUT8 1 byte per pixel, specifying the pen
number. On screen depths > 8 bits the
data is converted using the actual color
lookup table.
RECTFMT_GREY8 1 byte per pixel, specifying grey scale
value.
*/
/* This routine gets as input a struct ScreenNode * and a pointer to the data to be
displayed. This can be data which has just been decoded and needs to be displayed
immediately, but it could just as well be data that has been stored for later display */
void displaypicture(struct ScreenNode *sn,struct DisplayData *dd) {
WORD offsetleft;
UBYTE *buf;
UBYTE *scalebuf=0;
ULONG format;
UWORD bpr;
UWORD row=dd->row;
UBYTE repeatrow;
UWORD drawrow;
UWORD rowstodec=dd->rowstodec;
UBYTE cybertrue=(CyberGfxBase!=0 && IsCyberModeID(sn->modeid));
LONG scalemul;
LONG scalemasked;
struct LineHeader *lh=dd->lh;
buf=(UBYTE *)dd+sizeof(struct DisplayData);
if(sn->colorinput==CI_PALETTE || sn->colorinput==CI_GRAY) {
format=RECTFMT_LUT8;
bpr=sn->width;
}
else {
format=RECTFMT_RGB;
bpr=sn->width*3;
}
offsetleft=(*sn->scrchoice->nomw-sn->renderw)>>1;
if(offsetleft<0) {
offsetleft=0;
}
if(sn->scalexfactor==4096 || (scalebuf=AllocVec(sn->renderw*sn->bytesperpixel+4,MEMF_PUBLIC))!=0) {
while(rowstodec--!=0) {
repeatrow=lh->repeatrow;
row=lh->row;
while(repeatrow--!=0 && row<sn->height) {
scalemul=sn->scaleyfactor*row;
scalemasked=scalemul & 0xFFFFF000;
scalemul+=sn->scaleyfactor;
while(scalemul>scalemasked) {
scalemul-=4096;
// if((scalemul & 4095)<sn->scaleyfactor) {
drawrow=(scalemul>>12)+wbfontysize;
if(sn->scalexfactor!=4096) {
if(sn->colorinput==CI_PALETTE || sn->colorinput==CI_GRAY) {
SCALEGRAY(buf,scalebuf,sn->width,sn->scalexfactor);
}
else {
SCALERGB(buf,scalebuf,sn->width,sn->scalexfactor);
}
}
if(cybertrue!=0) {
WritePixelArray(scalebuf!=0 ? scalebuf : buf,0,0,bpr,&sn->screen->RastPort,offsetleft,drawrow,sn->renderw,1,format);
}
else {
WritePixelLine8(&sn->screen->RastPort,offsetleft,drawrow,sn->renderw,scalebuf!=0 ? scalebuf : buf,&sn->temprp);
}
}
row++;
}
lh++;
buf+=bpr;
}
if(scalebuf!=0) {
FreeVec(scalebuf);
}
}
}
/* Works for both normal and minimal listheaders */
void InitList(struct List *list) {
list->lh_Head=(struct Node *)&list->lh_Tail;
list->lh_Tail=0;
list->lh_TailPred=(struct Node *)&list->lh_Head;
}
ULONG __saveds __asm bfillhookfunc(register __a0 struct Hook *hook,register __a2 APTR object,register __a1 APTR message) {
return(0);
}
struct BitMap *CreateBitMap(LONG width, LONG height, LONG depth)
{
struct BitMap *bm;
if(SysBase->LibNode.lib_Version>=39) {
bm = AllocBitMap(width, height, depth, 0, NULL);
}
else
{
if (bm = AllocMem(sizeof(struct BitMap), MEMF_CLEAR | MEMF_PUBLIC))
{
LONG rassize = RASSIZE(width, height);
InitBitMap(bm, depth, width, height);
/* For simplicity, we allocate all planes in one big chunk */
if (bm->Planes[0] = (PLANEPTR) AllocVec(depth * rassize, MEMF_CHIP))
{
LONG i;
for (i = 1; i < depth; i++)
{
bm->Planes[i] = bm->Planes[i - 1] + rassize;
}
}
else
{
FreeMem(bm, sizeof(struct BitMap));
bm = NULL;
}
}
}
return (bm);
}
static void DeleteBitMap(struct BitMap *bm)
{
if (bm)
{
if(SysBase->LibNode.lib_Version>=39) {
FreeBitMap(bm);
}
else
{
FreeVec(bm->Planes[0]);
FreeMem(bm, sizeof(struct BitMap));
}
}
}
static ULONG BitMapDepth(struct BitMap *bm)
{
if(SysBase->LibNode.lib_Version>=39) {
return (GetBitMapAttr(bm, BMA_DEPTH));
}
else
{
return (bm->Depth);
}
}
/*
RecogniseXXX routines:
* Inputs:
- FileHandle
* Results:
- TRUE (if file is valid) or FALSE
InitXXX routines:
* Inputs:
- FileHandle
- struct ScreenNode *
* Results:
- ERROR_INVALID_FILE
- ERROR_EMPTY_FILE
- ERROR_UNKNOWN_COMPRESSION
- ERROR_UNSUPPORTED_DEPTH
- ERROR_NO_FREE_STORE
- 0 (if file is ready to be decoded)
- FileHandle is updated ready to be used by the DecodeXXX routine
- struct ScreenNode * is filled with all the needed information
ExitXXX routines:
* Inputs:
- struct ScreenNode *
* Purpose of these routines is to free any resources allocated by the InitXXX
routines.
DecodeXXX routines:
* Inputs:
- Callback Hook to process each decoded line (OutputLineRTN)
- FileHandle
- struct ScreenNode *
* Results:
- ERROR_WHILE_DECODING (invalid data)
* Info:
The CallBack hook returns several errors, which are passed through to
DecodeXXX which in turn passes them through to its caller. They are:
- USER_NEXT
- USER_EXIT
- 0 (no error, continue decoding)
*/
/*
ULONG bestmodeid(struct ScreenNode *sn,STRPTR pattern) {
ULONG lastid=INVALID_ID;
struct NameInfo name;
struct DimensionInfo dimension;
struct DisplayInfo display;
ULONG n3;
WORD aspect,picaspect,n,bestsize=32767,size;
UWORD depth,n2;
UBYTE direct,rerender,deep,gray,halvewidth;
ULONG bestmode=~0;
n2=sn->aspecty;
if(n2==0) {
n2=1;
}
n3=(ULONG)(sn->aspectx);
n3=(n3+n3+n3)<<6;
picaspect=n3/n2;
if(arglist.debug!=0) {
ULONG arg[4];
arg[0]=sn->depth;
arg[1]=picaspect;
arg[2]=sn->width;
arg[3]=sn->height;
VPrintf("\n-- INPUT -- Depth: %2ld Ratio: $%04lx (%ldx%ld)\n\n",&arg);
}
while((lastid=NextDisplayInfo(lastid))!=INVALID_ID) {
if((GetDisplayInfoData(0,(UBYTE *)&name,sizeof(struct NameInfo),DTAG_NAME,lastid))!=0) {
if((GetDisplayInfoData(0,(UBYTE *)&display,sizeof(struct DisplayInfo),DTAG_DISP,lastid))!=0) {
if((GetDisplayInfoData(0,(UBYTE *)&dimension,sizeof(struct DimensionInfo),DTAG_DIMS,lastid))!=0) {
if((arglist.screenmode==0) || (MatchPatternNoCase(pattern,name.Name)==TRUE)) {
aspect=((display.Resolution.x)<<8)/display.Resolution.y;
n=16384;
while(aspect<n) {
n>>=1;
}
if((aspect-n)>=(n>>1)) {
aspect=n<<1;
}
else {
aspect=n;
}
n=dimension.StdOScan.MaxX+1-sn->width;
if(n<0) {
n=-4*n;
}
size=dimension.StdOScan.MaxY+1-sn->height;
if(size<0) {
size=-4*size;
}
size+=n;
depth=dimension.MaxDepth;
direct=FALSE;
deep=FALSE;
gray=FALSE;
halvewidth=FALSE;
rerender=FALSE;
if((display.PropertyFlags & DIPF_IS_FOREIGN)!=0) {
goto rerender;
}
if((sn->ham==TRUE) || (sn->ehb==TRUE)) {
if((depth==8) || ((sn->depth==6) && depth>=5)) {
direct=TRUE;
}
}
rerender:
if((depth<sn->depth) && (direct==FALSE)) {
rerender=TRUE;
if(((display.PropertyFlags & DIPF_IS_FOREIGN)==0) && (arglist.gray==0) && (depth>=5)) {
/* didn't check forced gray... */
/* rerendering in HAM6/8 */
if(aspect>picaspect) {
halvewidth=TRUE;
aspect>>=1;
}
}
else {
/* rerendering in GRAY4/8 */
gray=TRUE;
}
if(depth==8) {
deep=TRUE;
}
}
/* all relevant info has been gathered for this screenmode, now let's
see if it is better than our best screenmode as of yet */
if(arglist.debug!=0) {
ULONG arg[7];
arg[0]=display.Header.DisplayID;
arg[1]=display.PropertyFlags;
arg[2]=(rerender&0x01)+((gray&0x01)<<1)+((deep&0x01)<<2)+((halvewidth&0x01)<<3)+((direct&0x01)<<4);
arg[3]=aspect;
arg[4]=size;
arg[5]=dimension.StdOScan.MaxX+1;
arg[6]=dimension.StdOScan.MaxY+1;
VPrintf("ID: $%08lx PFlags: $%08lx Bits: $%1lx Ratio: $%04lx Size: $%04lx (%ldx%ld)\n",&arg);
}
aspect-=picaspect;
if(aspect<0) {
aspect=-aspect;
}
if(bestmode!=~0) {
if(sn->rerender==FALSE) {
if(rerender==TRUE) {
goto donotusethisid;
}
}
else {
if(rerender==FALSE) {
goto usethisid;
}
if(arglist.gray!=0) {
/* check forced gray */
goto rendertypesame;
}
if(gray==TRUE) {
goto donotusethisid;
}
}
rendertypesame:
if(aspect>sn->renderaspect) {
goto donotusethisid;
}
else if(aspect<sn->renderaspect) {
goto usethisid;
}
if(size>bestsize) {
goto donotusethisid; /* continue ?? */
}
}
usethisid:
bestmode=display.Header.DisplayID;
sn->renderaspect=aspect;
sn->direct=direct;
sn->deep=deep;
sn->halvewidth=halvewidth;
sn->gray=gray;
sn->rerender=rerender;
bestsize=size;
sn->nominalw=dimension.StdOScan.MaxX;
sn->nominalh=dimension.StdOScan.MaxY;
donotusethisid:
}
}
}
}
}
return(bestmode);
}
*/
/*
After every linedecode a getmsg routine is called which checks the user's actions. This
routine is called from the main-decoder loop which under normal circumstances just processes
picture after picture and stores them into memory.
When the user wants to advance to the next picture then there are two states which we need
to take into account: A - The decoder is still decoding the current picture
B - The decoder is working on some other picture to be displayed later
These cases need different handling. In case A the decoding routines still may still hold
buffer memory for their decoding actions, which must be freed. In case B this is already
done. In both cases however the main-decoder should take care of freeing the ScreenNode.
*/
/*
AUTOSCALING
This feature kicks in when the screen is too large to be
opened in case of lack of (chip) memory. In this case
FastView tries to scale down the picture (to a certain
degree) and displays the result. When this fails as well
then FastView will return an error and continue to display
the next picture.
ORDER/K
This allows you to change the order in which the pictures
are displayed.
"A" : sorts the files alphabetically by their filename
"P" : sorts the files alphabetically by their full path name
"R" : random
The default is to display the pictures in the order they
were entered on the commandline or, in the case of
wildcards, in the order they were found in the directory.
If you specify a string not beginning with one of the
letters described above then this keyword will default to
using the random order.
Note: Only the first letter is checked for this keyword, so it
is possible to specify things like "ORDER=alphabetical"
or "ORDER=random" to get the desired results.
INFO/K
This option displays information above the picture. It
allows you to specify a formatting string to customize the
information. If you specify 'INFO=""' then the default
formatting string (see below) is used.
To customize the information string you simply specify a
string after the keyword. The string can contain these
special character sequences which will be automagically
replaced:
%N = the complete path plus the name of the picture
%n = the name of the picture (without path)
%x = the horizontal size of the picture in pixels (not
taking scaling into account)
%y = the vertical size of the picture in pixels (not
taking scaling into account)
%d = the depth of the picture on disk (not the depth
of the screen!)
%% = gives you a single '%'-character
The default string looks like this: "%n (%xx%yx%d)" which
for example could result into:
Test.jpg (640x480x24)
for a color JPEG picture named 'Test.jpg' of 640x480 pixels.
F1/K, F2/K, F3/K, F4/K, F5/K, F6/K, F7/K, F8/K, F9/K, F10/K
These options allow you to define a custom function for each
of the function keys. The specified function will be
executed each time you press the corresponding function key.
FastView will advance to the next picture when the function
has completed.
Examples (also see the INFO/K option for a description of
the special '%' character sequences):
F1="Copy %N PICS:Sorted/Cars/Lamborghini/"
Pressing F1 will copy the picture to
PICS:Sorted/Cars/Lamborghini - %N is automatically
replaced by the full pathname of the picture. Be warned
however that the C/Copy command simply replaces any
picture of the same name in the destination directory.
F5="Rename %N :Trashcan/%n"
F5 will 'move' the picture into the trashcan directory
on the same drive. Note that %n is replaced by just the
name of the picture, without its path. Note that unlike
C/Copy, C/Rename will fail when there is already a
picture of the same name in the destination directory.
F10="Delete %N"
F10 now simulates the behaviour of the Shift + Del
function of FastView.
*/